﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace FoundationLib.Common.Extensions
{
	/// <summary>
	/// A set of extensions to type <see cref="String"/>.
	/// </summary>
	public static class StringExtensions
	{
		/// <summary>
		/// Converts the first character of this string to upper case and returns the result.
		/// </summary>
		/// <param name="value">The string to convert</param>
		/// <returns>The conversion result</returns>
		public static string ToFirstUpper(this string value)
		{
			if (String.IsNullOrWhiteSpace(value))
				return value;

			return (value[0].ToString().ToUpper() + value.Substring(1));
		}

		/// <summary>
		/// Converts the first character of this string to lower case and returns the result.
		/// </summary>
		/// <param name="value">The string to convert</param>
		/// <returns>The conversion result</returns>
		public static string ToFirstLower(this string value)
		{
			if (String.IsNullOrWhiteSpace(value))
				return value;

			return (value[0].ToString().ToLower() + value.Substring(1));
		}

		/// <summary>
		/// Applies the given arguments to this string format.
		/// </summary>
		/// <param name="value">The string format</param>
		/// <param name="args">The arguments</param>
		/// <returns>The resulting string</returns>
		public static string FormatWith(this string value, params object[] args)
		{
			return (value != null ? String.Format(value, args) : null);
		}

		/// <summary>
		/// Wraps the given string so that it meets the given maximum line length constraints.
		/// </summary>
		/// <param name="value">The input string</param>
		/// <param name="maxLineLength">The maximum number of characters per line</param>
		/// <param name="lineSeparator">The string to use as a line separator</param>
		/// <returns>The wrapped string meeting the maximum line length constraints</returns>
		public static string Wrap(this string value, int maxLineLength, string lineSeparator)
		{
			if (String.IsNullOrWhiteSpace(value))
				return value;

			StringBuilder sb = new StringBuilder();
			string[] words = value.ToString().Split(' ');
			bool initial = true;

			foreach (string word in words)
			{
				if (!initial)
					sb.Append(" ");
				if (word.Length > maxLineLength)
				{
					int splitIterations = (int)Math.Ceiling((double)word.Length / (double)maxLineLength);
					int offset = 0;
					for (int i = 0; i < splitIterations; i++)
					{
						offset = i * maxLineLength;
						if (i == (splitIterations - 1))
							sb.Append(word.Substring(offset));
						else
							sb.Append(word.Substring(offset, maxLineLength))
								.Append(lineSeparator);
					}
				}
				else
				{
					sb.Append(word);
				}
				initial = false;
			}
			return sb.ToString();
		}

		/// <summary>
		/// Tries to convert the input string into a global unique identifier (GUID).
		/// </summary>
		/// <param name="value">The input string</param>
		/// <returns>The global unique identifier representing the input string or an empty GUID otherwise</returns>
		public static Guid ToGuid(this string value)
		{
			return ToGuid(value, false);
		}

		/// <summary>
		/// Tries to convert the input string into a global unique identifier (GUID).
		/// </summary>
		/// <param name="value">The input string</param>
		/// <param name="throwOnError">A value indicating whether an exception should be thrown if the conversion fails</param>
		/// <returns>The global unique identifier representing the input string or an empty GUID otherwise</returns>
		public static Guid ToGuid(this string value, bool throwOnError)
		{
			Guid result = Guid.Empty;
			bool parseResult = false;

			parseResult = Guid.TryParse(value, out result);
			if (!parseResult && throwOnError)
				throw new FormatException("The format of g is invalid.");

			return result;
		}

		/// <summary>
		/// Wraps the given string so that it meets the given maximum line length constraints. 
		/// </summary>
		/// <remarks>
		/// This method uses the environment's default line separator (usually CR LF).
		/// </remarks>
		/// <param name="value">The input string</param>
		/// <param name="maxLineLength">The maximum number of characters per line</param>
		/// <returns>The wrapped string meeting the maximum line length constraints</returns>
		public static string Wrap(this string value, int maxLineLength)
		{
			return Wrap(value, maxLineLength, Environment.NewLine);
		}
	}
}
